//  IDVI 1.0 source copyright 1996 Garth A. Dickie
//
//  This source is free for non-commercial use.  No warranty, etc.
//  Please acknowledge reuse by including the line:
//
//  "Based in part on IDVI 1.0 source copyright 1996 Garth A. Dickie"
//
//  in your documentation and source code.  For commercial use or
//  distribution, please contact the author.  Please also send
//  questions, comments, bug reports, or fixes.
//
//  Best Regards,
//  Garth A. Dickie
//  dickie@elastic.avid.com

package ibook.v10.idvi.font;

import java.io.InputStream;
import java.io.IOException;

import ibook.v10.idvi.IDVI;
import ibook.v10.idvi.io.DVIInputStream;

public class PKFont extends DVIFont implements Runnable {
    final private static int    kMagic = 0xF759;
    final private static int    kCommandX1 = 240;
    final private static int    kCommandX2 = 241;
    final private static int    kCommandX3 = 242;
    final private static int    kCommandX4 = 243;
    final private static int    kCommandY = 244;
    final private static int    kCommandPOST = 245;
    final private static int    kCommandNOOP = 246;
    final private static int    kCommandPRE = 247;
    final private static int    kCommand248 = 248;
    final private static int    kCommand249 = 249;
    final private static int    kCommand250 = 250;
    final private static int    kCommand251 = 251;
    final private static int    kCommand252 = 252;
    final private static int    kCommand253 = 253;
    final private static int    kCommand254 = 254;
    final private static int    kCommand255 = 255;

    private String              name;
    private int                 size;
    private long                checksum;
    private PKCharacter[ ]      character = new PKCharacter[ 256 ];
    private boolean             doneLoading = false;
    private DVIInputStream      source;

    private void decodeCharacter( DVIInputStream source, int flags )
            throws IOException, PKFormatException {

        int byteCount;
        int index;
        int integerSize;

        if(( flags & 0x7 ) == 0x7 ) {
            byteCount = source.unsigned4( );
            index = source.unsigned4( );
            integerSize = 4;
        } else if(( flags & 0x4 ) == 0x4 ) {
            byteCount = (( flags & 0x3 ) << 16 ) + source.unsigned2( );
            index = source.unsigned1( );
            integerSize = 2;
        } else {
            byteCount = (( flags & 0x3 ) << 8 ) + source.unsigned1( );
            index = source.unsigned1( );
            integerSize = 1;
        }

        int dynf = flags >> 4;
        boolean paint = ( flags & 0x8 ) != 0;

        setCharacter( index, new PKCharacter( source, dynf, paint, integerSize, byteCount ));
    }

    public PKFont( InputStream inputStream, String name, int size )
            throws IOException, PKFormatException {
        
        super( name + "." + size + "pk" );

        this.name = name;
        this.size = size;

        source = new DVIInputStream( inputStream );

        if( source.unsigned2( ) != kMagic )
            throw new PKFormatException( "PKFont: not a PK file\n" );

        source.skip( source.unsigned1( ));  //  comment
        source.skip( 4 );                   //  design size
        checksum = source.unsigned4( );     //  checksum to compare with dvi file
        source.skip( 8 );                   //  hppp and vppp

        Thread loader = new Thread( this );
        loader.start( );
    }




    private int clientCount = 0;

    public synchronized DVICharacter getCharacter( int index ) {
        if( index >= 0 && index < character.length ) {
            if( character[ index ] == null && ! doneLoading ) {
                ++ clientCount;

                while( character[ index ] == null && ! doneLoading )
                    try {
                        wait( );
                    } catch( InterruptedException e ) {
                    }
                
                -- clientCount;
            }
            return character[ index ];
        } else
            return null;
    }

    private synchronized void setCharacter( int index, PKCharacter newCharacter ) {
        character[ index ] = newCharacter;
        if( clientCount != 0 )
            notifyAll( );
        else
            Thread.currentThread( ).yield( );
    }

    private synchronized void setDoneLoading( ) {
        doneLoading = true;
        if( clientCount != 0 )
            notifyAll( );
    }




    public void run( ) {
        Thread.currentThread( ).setPriority( IDVI.kPriorityLoadFont );

        if( IDVI.debugFontLog )
            System.out.println( "Loading font \"" + name + "\" at " + size + "dpi" );

        try {
            boolean done = false;
            while( ! done ) {
                int command = source.unsigned1( );
                switch( command ) {
                    default:            decodeCharacter( source, command ); break;
                    case kCommandX1:    source.skip( source.unsigned1( ));  break;
                    case kCommandX2:    source.skip( source.unsigned2( ));  break;
                    case kCommandX3:    source.skip( source.unsigned3( ));  break;
                    case kCommandX4:    source.skip( source.unsigned4( ));  break;
                    case kCommandY:     source.skip( 4 );                   break;
                    case kCommandPOST:  done = true;                        break;
                    case kCommandNOOP:                                      break;
                    case kCommandPRE:
                        throw new PKFormatException(
                            "PKFont: unexpected PRE in body of font file." );
                    case kCommand248:
                    case kCommand249:
                    case kCommand250:
                    case kCommand251:
                    case kCommand252:
                    case kCommand253:
                    case kCommand254:
                    case kCommand255:
                        throw new PKFormatException(
                            "PKFont: undefined command " + command + "." );
                }
            }
            source.close( );
        } catch( Exception e ) {
            System.err.println( e );
        }

        setDoneLoading( );

        if( IDVI.debugFontLog )
            System.out.println( "Done loading font \"" + name + "\" at " + size + "dpi" );
    }
}
